package gui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.BoxLayout;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

import urbanparks.Job;
import urbanparks.JobGrade;
import urbanparks.Park;
import urbanparks.ParkManager;
import urbanparks.User;
import urbanparks.UserSet;
import urbanparks.Volunteer;

/**
 * A custom JDialog that displays information about a
 * job.
 * 
 * @author Michelle Miller
 * @version Winter 2012
 */
@SuppressWarnings("serial")
public class JobInformationForm extends JDialog {
  
  /**
   * A reference to the job to be displayed in this
   * dialog.
   */
  private final Job my_job;
  
  /** A reference to the controller. */
  private UrbanParksManagerFrame my_manager;
  
  /** 
   * The JPanel that contains all of the components
   * displayed on this dialog. 
   */
  private JPanel my_form;
  
  /** A reference to the volunteer button. */
  private JButton my_volunteer;
  
  /** A reference to the view volunteer list button. */
  private JButton my_viewList;
  
  /** A reference to the cancel button. */
  private JButton my_cancel;
  
  /** 
   * A reference to the label displaying the number of
   * volunteers needed at the low grade. 
   */
  private JLabel my_l_vol_needed;
  
  /** 
   * A reference to the label displaying the number of
   * volunteers needed at the medium grade. 
   */
  private JLabel my_m_vol_needed;
  
  /** 
   * A reference to the label displaying the number of
   * volunteers needed at the heavy grade. 
   */
  private JLabel my_h_vol_needed;

  /**
   * Constructor for the JobInformationForm that
   * populates the display with the job information and
   * selected navigation buttons based on the current
   * user's permissions.
   * 
   * @param the_job The job to display to the information
   *  of in the dialog.
   */
  public JobInformationForm(final Job the_job,
      final UrbanParksManagerFrame the_manager) {
    super(the_manager, "Job Information");
    my_manager = the_manager;
    my_job = the_job;
    final int permissions = 
        my_manager.getCurrentUser().getPermissionLevel();
    initForm(permissions);
    this.setContentPane(my_form);
    this.pack();
    
  }

  /**
   * Private helper method that populates the panel
   * containing all of the components.
   * 
   * @param the_permissions The permissions of the current
   *  user.
   */
  private void initForm(final int the_permissions) {
    my_form = new JPanel(new BorderLayout());
    final JPanel info = getInfoPanel();
    final JPanel buttons = initButtonPanel(the_permissions);
    my_form.add(info, BorderLayout.CENTER);
    my_form.add(buttons, BorderLayout.SOUTH);
    
  }

  /**
   * Private helper method that returns a JPanel containing
   * the buttons to be displayed based on the permissions
   * provided.
   * 
   * @param the_permissions The permissions of the current
   *  user
   * @return A JPanel that contains the buttons to be
   *  displayed that is determined by the current user's
   *  permissions.
   */
  private JPanel initButtonPanel(
      final int the_permissions) {
    final JPanel buttonPanel = new JPanel();
    
    my_volunteer = getVolunteerButton();
    my_viewList = getViewVolunteersButton();
    my_cancel = getCloseButton();
    
    if (the_permissions == UserSet.USER_VOLUNTEER &&
        my_job.isPendingJob() &&
        !my_job.containsVolunteer(
            my_manager.getCurrentUser().
            getEmailAddress())) {
      buttonPanel.add(my_volunteer);
    }
    if (the_permissions == UserSet.USER_STAFF) {
      buttonPanel.add(my_viewList);
    }
    buttonPanel.add(my_cancel);
    return buttonPanel;
  }
  
  /**
   * Private helper method that updates the labels
   * displaying the current volunteers needed at each
   * grade difficulty.
   */
  public void updateVolNeededLabels() {
    my_l_vol_needed.setText(
        my_job.getGrade(
            Job.LIGHT_GRADE).getCurrentNeeded() +
        " volunteers needed.");
    
    my_m_vol_needed.setText(
        my_job.getGrade(
            Job.MEDIUM_GRADE).getCurrentNeeded() +
        " volunteers needed.");
    
    my_h_vol_needed.setText(
        my_job.getGrade(
            Job.HEAVY_GRADE).getCurrentNeeded() +
        " volunteers needed.");
  }

  /**
   * Private helper method that returns a JButton with the
   * label "Close" and the action of closing this
   * JobInformationForm.
   * 
   * @return A JButton that closes this dialog.
   */
  private JButton getCloseButton() {
    JButton closeButton = new JButton("Close");
    closeButton.addActionListener(new ActionListener() {
      public void actionPerformed(
          final ActionEvent the_e) {
        JobInformationForm.this.dispose();
      }
    });
    return closeButton;
  }

  /**
   * Private helper method that returns a JButton with the
   * label "View Volunteers" and the action of displaying a
   * new dialog displaying the list of volunteers signed up
   * for this job.
   * 
   * @return A JButton that opens a ViewVolunteersDialog.
   */
  private JButton getViewVolunteersButton() {
    JButton viewVolButton =
        new JButton("View Volunteer List");
    viewVolButton.addActionListener(new ActionListener() {
      public void actionPerformed(
          final ActionEvent the_e) {
        final ViewVolunteers viewVolunteers = 
            new ViewVolunteers();
        viewVolunteers.setVisible(true);
      }
    });
    return viewVolButton;
  }
  
  /**
   * Private helper method that returns a JButton with the
   * label "Volunteer" and the action of displaying a
   * new dialog displaying a list of job grades for the
   * user to sign up with
   * 
   * @return A JButton that opens a VolunteerDialog.
   */
  private JButton getVolunteerButton() {
    final JButton volButton = new JButton("Volunteer");
    volButton.addActionListener(new ActionListener() {

      public void actionPerformed(
          final ActionEvent the_e) {
        final VolunteerForm v = new VolunteerForm();
        v.setVisible(true);
        
      }
    });
    return volButton;
  }

  /**
   * Private helper method that returns a JPanel containing
   * all of the information on the job.
   * 
   * @return A JPanel with the job information.
   */
  private JPanel getInfoPanel() {
    final JPanel infoPanel = new JPanel();
    
    final Park park = 
        my_manager.getParkSet().getPark(my_job.getPark());
    final ParkManager pm =
        (ParkManager) my_manager.getUserSet().getUser(
            park.getManagerEmail());
    
    infoPanel.setLayout(
        new BoxLayout(infoPanel, BoxLayout.PAGE_AXIS));
    
    infoPanel.add(new JLabel(
        "Date Received: " + my_job.getDateReceived()));
    infoPanel.add(new JLabel(
        "Received By: " + my_job.getReceivedBy()));
    infoPanel.add(new JLabel(
        "Park Name: " + my_job.getPark()));
    infoPanel.add(new JLabel(
        "Park Manager: " + pm.getFullName()));
    infoPanel.add(new JLabel(
        "Manager's Phone: " + pm.getPhoneNumber()));
    infoPanel.add(new JLabel(
        "Park District: " + park.getParkDistrict()));
    infoPanel.add(new JLabel(
        "Job Description: " + my_job.getJobDescription()));
    infoPanel.add(new JLabel(
        "Job Date: " +
            my_job.getJobDuration().toString()));
    infoPanel.add(new JLabel("Number of volunteers needed" +
        " and work description at each grade level: "));
    
    infoPanel.add(new JLabel("Light:"));
    my_l_vol_needed = new JLabel(
        my_job.getGrade(Job.LIGHT_GRADE).getCurrentNeeded() +
        " volunteers needed.");
    infoPanel.add(my_l_vol_needed);
    infoPanel.add(new JLabel(
        my_job.getGrade(Job.LIGHT_GRADE).getDescription()));
    
    infoPanel.add(new JLabel("Medium:"));
    my_m_vol_needed = new JLabel(
        my_job.getGrade(
            Job.MEDIUM_GRADE).getCurrentNeeded() +
        " volunteers needed.");
    infoPanel.add(my_m_vol_needed);
    infoPanel.add(new JLabel(
        my_job.getGrade(Job.MEDIUM_GRADE).
        getDescription()));
    
    infoPanel.add(new JLabel("Heavy:"));
    my_h_vol_needed = new JLabel(
        my_job.getGrade(Job.HEAVY_GRADE).
        getCurrentNeeded() +
        " volunteers needed.");
    infoPanel.add(my_h_vol_needed);
    infoPanel.add(new JLabel(
        my_job.getGrade(Job.HEAVY_GRADE).
        getDescription()));
    
    infoPanel.add(new JLabel(
        "Public transportation to job site: " +
            park.getPublicTransportationDirections()));
    infoPanel.add(new JLabel(
        "Driving directions to job site: " +
            park.getDrivingDirections()));
    return infoPanel;
  }

  /**
   * Class that displays the list of volunteers currently
   * signed up for a job.
   * 
   * @author Michelle Miller
   * @version Winter 2012
   */
  private class ViewVolunteers extends JDialog {
  
    /**
     * Constructor for the ViewVolunteers dialog.
     */
    public ViewVolunteers() {
      super(my_manager, "View Volunteers");
      this.setContentPane(getForm());
      this.pack();
      this.setMinimumSize(this.getSize());
    }
  
    /**
     * Private helper method gets a JPanel containing all
     * of the components displayed in this dialog.
     * 
     * @return A JPanel containing all of the components
     *  displayed in this dialog.
     */
    private JPanel getForm() {
      final JPanel form = new JPanel(new BorderLayout());
      
      final List<String> volunteerList =
          my_job.getVolunteerListNoGrade();
      final JPanel userPanel = new JPanel();
      userPanel.setLayout(new GridLayout(0, 1));
      
      if (volunteerList.size() == 0) {
        userPanel.add(new JLabel(
            "There are no volunteers to display."));
      }
      
      for (String s : volunteerList) {
        userPanel.add(getUserPanel(s));
      }
      
      form.add(userPanel, BorderLayout.CENTER);
      form.add(getinitButtonPanel(), BorderLayout.SOUTH);
      return form;
    }
    
    /**
     * Private helper method that gets a JPanel containing
     * the buttons to display.
     * 
     * @return A JPanel containing the buttons to display.
     */
    private JPanel getinitButtonPanel() {
      final JPanel buttonPanel = new JPanel();
      JButton closeButton = new JButton("Close");
      closeButton.addActionListener(new ActionListener() {
        public void actionPerformed(
            final ActionEvent the_e) {
          ViewVolunteers.this.dispose();
        }
      });
      buttonPanel.add(closeButton);
      return buttonPanel;
    }
    
    /**
     * Private helper method that returns a JPanel
     * containing the user's name and a button to blackball
     * the user.
     * 
     * @param the_user_email The email of the user to
     *  display.
     * @return A JPanel containing the user's name and a
     *  JButton to blackball the user.
     */
    private JPanel getUserPanel(
        final String the_user_email) {
      final JPanel userPanel = new JPanel();
      final User user = my_manager.getUserSet().getUser(the_user_email);
      final JLabel nameLabel = new JLabel(user.getFullName());
      final JButton blackball =
          new JButton("Blackball");
      blackball.addActionListener(
          new ActionListener() {
  
            public void actionPerformed(
                final ActionEvent the_e) {
              ((Volunteer) user).blackball();
              final String errorMsg =
                  "<html><center>You have blackballed " +
                      user.getFullName() +
                      "</center></html>";
              JOptionPane.showMessageDialog(my_manager,
                                            errorMsg);
              blackball.setVisible(false);
              updateVolNeededLabels();
            }
          });
      userPanel.add(nameLabel);
      if (!((Volunteer) user).isBlackballed()) {
        userPanel.add(blackball);
      }
      return userPanel;
    }
    
  }


  /**
   * A custom JDialog that displays a dropdown menu listing
   * the available grades to sign-up with and buttons
   * allowing the user to either volunteer at the selected
   * grade or to cancel.
   * 
   * @author Michelle Miller
   * @version Winter 2012
   */
  private class VolunteerForm extends JDialog {
    
    /** A reference to the grade selection JComboBox. */
    private JComboBox my_combo_box;
    
    /**
     * The available grade to populate the combo box with.
     */
    private final JobGrade[] grades = 
      {my_job.getGrade(Job.LIGHT_GRADE),
        my_job.getGrade(Job.MEDIUM_GRADE),
        my_job.getGrade(Job.HEAVY_GRADE)};
    
    /**
     * Constructor for the VolunteerForm dialog.
     */
    public VolunteerForm() {
      super(my_manager, "Volunteer Sign Up");
      this.setContentPane(getForm());
      this.pack();
      this.setMinimumSize(this.getSize());
    }

    /**
     * Private helper method that gets the JPanel
     * containing all of the components displayed in this
     * dialog.
     * 
     * @return A JPanel containing all of the elements
     *  displayed in this dialog.
     */
    private JPanel getForm() {
      final JPanel form = new JPanel(new BorderLayout());
      final JPanel comboBoxPanel = new JPanel();
      initializeComboBox();
      comboBoxPanel.add(new JLabel(
          "Please select a work difficulty:"));
      comboBoxPanel.add(my_combo_box);
      
      form.add(comboBoxPanel, BorderLayout.CENTER);
      form.add(getButtonPanel(), BorderLayout.SOUTH);
      return form;
    }
    
    /**
     * Initializes the grade display combobox, with the
     * elements in my_grades and with tooltips with the
     * grade descriptions.
     */
    private void initializeComboBox() {
      final List<String> desc = new ArrayList<String>();
      my_combo_box = new JComboBox();
      JobGradeToolTipRenderer renderer =
          new JobGradeToolTipRenderer();
      my_combo_box.setRenderer(renderer);

      for (int i = 0; i < grades.length; i++) {
        my_combo_box.addItem(grades[i].toString());
        desc.add(grades[i].getDescription());
      }
      
      renderer.setTooltips(desc);
      
    }

    /**
     * Returns a JPanel containing the buttons to display.
     * 
     * @return A JPanel containing the buttons to display.
     */
    private JPanel getButtonPanel() {
      final JPanel buttonPanel = new JPanel();
      buttonPanel.add(makeVolunteerButton());
      buttonPanel.add(getCancelButton());
      return buttonPanel;
    }

    /**
     * Returns a JButton to close this dialog.
     * 
     * @return A JButton that closes this dialog.
     */
    private JButton getCancelButton() {
      JButton cancelButton = new JButton("Cancel");
      cancelButton.addActionListener(new ActionListener() {
        public void actionPerformed(
            final ActionEvent the_e) {
          VolunteerForm.this.dispose();
        }
      });
      return cancelButton;
    }
    
    /**
     * Returns the JButton that performs the actions of
     * attempting to signup the volunteer for the job with
     * warnings displayed if an error occurred.
     * 
     * @return A JButton that attempts to signs the
     *  volunteer up for the job.
     */
    private JButton makeVolunteerButton() {
      JButton volButton = new JButton("Volunteer");
      volButton.addActionListener(new ActionListener() {
        public void actionPerformed(
            final ActionEvent the_e) {
          final JobGrade grade =
              grades[my_combo_box.getSelectedIndex()];
            boolean added = false;
            if (grade != null) {
              added = my_job.addVolunteer(
                  my_manager.getCurrentUser(),
                  grade, my_manager.getJobSet());
            }
            if (!added) {
              final String errorMsg =
                  "<html>You could not be added to the " +
                  "Volunteer list for this job.<br>" +
                  "<center>Please contact the office st" + 
                  "aff by phone or email.</center></html>";
              JOptionPane.showMessageDialog(my_manager,
                  errorMsg);
            } else {
              JobInformationForm.this.
                updateVolNeededLabels();
              JobInformationForm.this.
                my_volunteer.setVisible(false);
              VolunteerForm.this.dispose();
            }
          }
      });
      return volButton;
    }
    
    /**
     * Private custom ToolTipRenderer to display the
     * descriptions of the grades in the comboBox once
     * the mouse hovers over.
     * 
     * @author Michelle Miller
     * @version Winter 2012
     */
    private class JobGradeToolTipRenderer extends 
      DefaultListCellRenderer {
      
      /**
       * The tooltips to display.
       */
      private List<String> my_tooltips;

      /** 
       * Customization of the getListCellRendererComponent
       * method of the DefaultListCellRenderer class that
       * displays the tooltip in my_tooltips when the cell
       * with the corresponding index has focus.
       * 
       * @param
       */
      @Override
      public Component getListCellRendererComponent(
          final JList the_list, final Object the_value,
          final int the_index,
          final boolean the_isSelected,
          final boolean the_cellHasFocus) {

          JComponent component = (JComponent)
              super.getListCellRendererComponent(
                  the_list, the_value, the_index,
                  the_isSelected, the_cellHasFocus);

          if (the_index > -1 && the_value != null &&
              my_tooltips != null) {
            the_list.setToolTipText(
                my_tooltips.get(the_index));
          }
          return component;
      }

      /**
       * Sets my tooltips to be displayed.
       * 
       * @param the_tooltips The list of strings to set as
       *  my_tooltips
       */
      public void setTooltips(
          final List<String> the_tooltips) {
          this.my_tooltips = the_tooltips;
      }
    }
    

  }

}
